<template>
    <div>
      <!-- 子组件模板 -->
      <h3>子组件</h3>
      <div class="attrs-display">
        <p>子组件接收到的 $attrs:</p>
        <pre>{{ attrsDisplay }}</pre>
        
        <p>子组件声明的 props:</p>
        <p><strong>标题:</strong> {{ title }}</p>
        
        <button @click="triggerEvent">触发事件</button>
      </div>
      
      <!-- 
        将 $attrs 传递给孙组件
        v-bind="$attrs" 会将所有未被子组件声明为 props 的属性传递给孙组件
      -->
      <Grandson v-bind="$attrs" :title="title + ' (来自子组件)'" />
    </div>
  </template>
  
  <script lang="ts" setup>
  /**
   * $attrs 详解 - 子组件部分
   * 
   * 1. 访问 $attrs：
   *    - 在 <script setup> 中，可以通过 useAttrs() 函数访问 $attrs 对象
   *    - 在模板中，可以直接使用 $attrs
   * 
   * 2. 控制属性继承：
   *    - 默认情况下，未声明为 props 的属性会自动添加到组件的根元素上
   *    - 可以通过 inheritAttrs: false 选项禁止这种默认行为
   *    - 然后可以使用 v-bind="$attrs" 手动决定将属性应用到哪个元素上
   * 
   * 3. 属性透传：
   *    - 使用 v-bind="$attrs" 可以将所有未声明为 props 的属性传递给子组件
   *    - 这在创建包装组件或高阶组件时非常有用
   */
  
  import { computed, useAttrs } from 'vue';
  import Grandson from './grandson.vue';
  
  // 声明部分属性为 props（这些属性不会出现在 $attrs 中）
  const props = defineProps<{
    title: string; // 只接收 title 作为 prop
  }>();
  
  // 声明要触发的事件
  const emit = defineEmits<{
    (e: 'custom-event', payload: any): void;
  }>();
  
  // 使用 useAttrs() 获取所有未声明为 props 的属性
  const attrs = useAttrs();
  
  // 格式化 $attrs 用于显示
  const attrsDisplay = computed(() => {
    return JSON.stringify(attrs, null, 2);
  });
  
  // 触发自定义事件
  function triggerEvent() {
    emit('custom-event', {
      from: '子组件',
      text: '子组件触发的事件',
      time: new Date().toLocaleTimeString()
    });
  }
  
  /**
   * 4. 注意事项：
   *    4.1 $attrs 包含所有未被声明为 props 的属性，包括事件监听器
   *    4.2 在 Vue 3 中，class 和 style 属性也会包含在 $attrs 中
   *    4.3 $attrs 是响应式的，当父组件更新属性时，子组件会收到更新
   * 
   * 5. 与 props 的区别：
   *    - props 需要显式声明，而 $attrs 自动收集未声明的属性
   *    - props 可以设置默认值、类型验证等，而 $attrs 不行
   *    - 使用 props 的属性在组件内部可以直接访问，而 $attrs 需要通过 $attrs 对象访问
   */
  </script>
  
  <style scoped>
  /* 子组件样式 */
  div {
    background: linear-gradient(to right, #f6d365, #fda085);
    border-radius: 12px;
    padding: 20px;
    margin: 15px 0;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    transition: all 0.3s ease;
  }
  
  div:hover {
    transform: translateY(-5px);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  }
  
  h3 {
    color: #ffffff;
    font-size: 22px;
    margin-bottom: 15px;
    text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
    font-weight: 500;
    letter-spacing: 1px;
  }

  .attrs-display {
    background-color: rgba(255, 255, 255, 0.2);
    border-radius: 8px;
    padding: 15px;
    margin-bottom: 20px;
  }

  pre {
    background-color: rgba(0, 0, 0, 0.1);
    padding: 10px;
    border-radius: 5px;
    color: white;
    font-family: monospace;
    overflow-x: auto;
    margin: 10px 0;
  }

  button {
    background-color: white;
    color: #ff7e5f;
    border: none;
    padding: 8px 15px;
    border-radius: 6px;
    font-weight: bold;
    cursor: pointer;
    margin-top: 10px;
    transition: all 0.2s;
  }

  button:hover {
    background-color: #ff7e5f;
    color: white;
  }
  </style>